home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Graphics / GraphicsWorkshop / Source / Converters / GIF_SCRATCH / gifread.m < prev    next >
Encoding:
Text File  |  1992-03-07  |  12.0 KB  |  543 lines

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1990, David Koblas.                                     | */
  3. /* |   Permission to use, copy, modify, and distribute this software   | */
  4. /* |   and its documentation for any purpose and without fee is hereby | */
  5. /* |   granted, provided that the above copyright notice appear in all | */
  6. /* |   copies and that both that copyright notice and this permission  | */
  7. /* |   notice appear in supporting documentation.  This software is    | */
  8. /* |   provided "as is" without express or implied warranty.           | */
  9. /* +-------------------------------------------------------------------+ */
  10.  
  11. #import <stdio.h>
  12. #import <stdlib.h>
  13. #import <strings.h>
  14. #import <appkit/NXBitmapImageRep.h>
  15. #import <Converter.h>
  16. #import "kludge.h"
  17. #import "gifread.h"
  18.  
  19. #define    MAXCOLORMAPSIZE        256
  20.  
  21. #define    TRUE                        1
  22. #define    FALSE                        0
  23.  
  24. #define CM_RED                        0
  25. #define CM_GREEN                    1
  26. #define CM_BLUE                    2
  27.  
  28. #define    MAX_LWZ_BITS                12
  29.  
  30. #define INTERLACE                    0x40
  31. #define LOCALCOLORMAP            0x80
  32. #define BitSet(byte, bit)                (((byte) & (bit)) == (bit))
  33.  
  34. #define    ReadOK(file,buffer,len)        (NXRead(file, buffer, len) != 0)
  35.  
  36. #define LM_to_uint(a,b)                (((b)<<8)|(a))
  37.  
  38. struct {
  39.     unsigned int    Width;
  40.     unsigned int    Height;
  41.     unsigned char    ColorMap[3][MAXCOLORMAPSIZE];
  42.     unsigned int    BitPixel;
  43.     unsigned int    ColorResolution;
  44.     unsigned int    Background;
  45.     unsigned int    AspectRatio;
  46. } GifScreen;
  47.  
  48. struct {
  49.     int    transparent;
  50.     int    delayTime;
  51.     int    inputFlag;
  52.     int    disposal;
  53. } Gif89 = { -1, -1, -1, 0 };
  54.  
  55. //pixel            *Image = NULL;
  56. int                verbose = YES;
  57. int                showComment;
  58. static int            error;
  59.  
  60. static int ReadColorMap ( NXStream *fd, int number, unsigned char buffer[3][MAXCOLORMAPSIZE] );
  61. static int DoExtension ( NXStream *fd, int label );
  62. static int GetDataBlock( NXStream *fd, unsigned char  *buf);
  63. static int GetCode ( NXStream *fd, int code_size, int flag );
  64. static int LWZReadByte ( NXStream *fd, int flag, int input_code_size );
  65. static void ReadImage ( NXStream *fd, int len, int height, unsigned char cmap[3][MAXCOLORMAPSIZE], int interlace, int ignore );
  66.  
  67. int GIFError(void)
  68. {
  69.     return error;
  70. }
  71.  
  72. id ReadGIF(NXStream * fd, int imageNumber)
  73. {
  74.     unsigned char        buf[16];
  75.     unsigned char        c;
  76.     unsigned char        localColorMap[3][MAXCOLORMAPSIZE];
  77.     int                useGlobalColormap;
  78.     int                bitPixel;
  79.     int                imageCount = 0;
  80.     char                version[4];
  81.     BOOL            readImage = NO;
  82.  
  83.     if (! ReadOK(fd,buf,6)) {
  84.         error = ERROR_BAD_FORMAT;
  85.         return nil;
  86.     }
  87.  
  88.     if (strncmp((char *)buf,"GIF",3) != 0) {
  89.         error = ERROR_BAD_FORMAT;
  90.         return nil;
  91.     }
  92.  
  93.     strncpy(version, (char *)buf + 3, 3);
  94.     version[3] = '\0';
  95.  
  96.     if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
  97.         error = ERROR_BAD_FORMAT;
  98.         return nil;
  99.     }
  100.  
  101.     if (! ReadOK(fd,buf,7)) {
  102.         error = ERROR_BAD_FORMAT;
  103.         return nil;
  104.     }
  105.  
  106.     GifScreen.Width            = LM_to_uint(buf[0],buf[1]);
  107.     GifScreen.Height            = LM_to_uint(buf[2],buf[3]);
  108.     GifScreen.BitPixel            = 2<<(buf[4]&0x07);
  109.     GifScreen.ColorResolution    = (((buf[4]&0x70)>>3)+1);
  110.     GifScreen.Background        = buf[5];
  111.     GifScreen.AspectRatio        = buf[6];
  112.  
  113.     fprintf(stderr, "W %d\nH %d\nBit Pixel %d\nColorRes %d\nBG %d\nAspect %f\n",
  114.                             GifScreen.Width,
  115.                             GifScreen.Height,
  116.                             GifScreen.ColorResolution,
  117.                             GifScreen.Background,
  118.                             GifScreen.AspectRatio);
  119.  
  120.     if (BitSet(buf[4], LOCALCOLORMAP)) {        /* Global Colormap */
  121.         if (ReadColorMap(fd,GifScreen.BitPixel,GifScreen.ColorMap)) {
  122.             error = ERROR_BAD_FORMAT;
  123.             return nil;
  124.         }
  125.     }
  126.  
  127.     if (GifScreen.AspectRatio != 0 && GifScreen.AspectRatio != 49) {
  128.         float        r;
  129.  
  130.         r = ( (float) GifScreen.AspectRatio + 15.0 ) / 64.0;
  131.         fprintf(stderr, "warning - non-square pixels; to fix do a 'pnmscale -%cscale %g'",
  132.             r < 1.0 ? 'x' : 'y',
  133.             r < 1.0 ? 1.0 / r : r );
  134.     }
  135.  
  136.     for (;;) {
  137.         if (! ReadOK(fd,&c,1)) {
  138.             if (readImage) {
  139.                 return pm_close(fd);
  140.             }
  141.             error = ERROR_BAD_FORMAT;
  142.             return nil;
  143.         }
  144.  
  145.         if (c == ';') {        /* GIF terminator */
  146.             if (imageCount < imageNumber) {
  147.                 error = ERROR_BAD_FORMAT;
  148.                 return nil;
  149.             }
  150.             return pm_close(fd);
  151.         }
  152.  
  153.         if (c == '!') {     /* Extension */
  154.             if (! ReadOK(fd,&c,1)){
  155.                 error = ERROR_BAD_FORMAT;
  156.                 return nil;
  157.             }
  158.             DoExtension(fd, c);
  159.             continue;
  160.         }
  161.  
  162.         if (c != ',') {        /* Not a valid start character */
  163.             fprintf(stderr, "bogus character 0x%02x, ignoring\n", (int) c );
  164.             continue;
  165.         }
  166.  
  167.         ++imageCount;
  168.  
  169.         if (! ReadOK(fd,buf,9)) {
  170.             error = ERROR_BAD_FORMAT;
  171.             return nil;
  172.         }
  173.  
  174.         useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);
  175.  
  176.         bitPixel = 1<<((buf[8]&0x07)+1);
  177.  
  178.         if (! useGlobalColormap) {
  179.             if (ReadColorMap(fd, bitPixel, localColorMap)) {
  180.                 error = ERROR_BAD_FORMAT;
  181.                 return nil;
  182.             }
  183.             ReadImage(fd, LM_to_uint(buf[4],buf[5]),
  184.                   LM_to_uint(buf[6],buf[7]), localColorMap,
  185.                   BitSet(buf[8], INTERLACE), imageCount != imageNumber);
  186.             readImage = YES;
  187.         } else {
  188.             ReadImage(fd, LM_to_uint(buf[4],buf[5]),
  189.                   LM_to_uint(buf[6],buf[7]), GifScreen.ColorMap,
  190.                   BitSet(buf[8], INTERLACE), imageCount != imageNumber);
  191.             readImage = YES;
  192.         }
  193.     }
  194. }
  195.  
  196. static int ReadColorMap(    NXStream         *fd, 
  197.                         int             number, 
  198.                         unsigned char    buffer[3][MAXCOLORMAPSIZE])
  199. {
  200.     int            i;
  201.     unsigned        char    rgb[3];
  202.  
  203.     for (i = 0; i < number; ++i) {
  204.         if (! ReadOK(fd, rgb, sizeof(rgb)))
  205.             error = ERROR_BAD_FORMAT;
  206.  
  207.         buffer[CM_RED][i] = rgb[0] ;
  208.         buffer[CM_GREEN][i] = rgb[1] ;
  209.         buffer[CM_BLUE][i] = rgb[2] ;
  210.     }
  211.     return FALSE;
  212. }
  213.  
  214. static int DoExtension(NXStream *fd, int label)
  215. {
  216.     static char    buf[256];
  217.     char            *str;
  218.  
  219.     switch (label) {
  220.     case 0x01:        /* Plain Text Extension */
  221.         str = "Plain Text Extension";
  222. #ifdef notdef
  223.         if (GetDataBlock(fd, (unsigned char*) buf) == 0)
  224.             ;
  225.  
  226.         lpos   = LM_to_uint(buf[0], buf[1]);
  227.         tpos   = LM_to_uint(buf[2], buf[3]);
  228.         width  = LM_to_uint(buf[4], buf[5]);
  229.         height = LM_to_uint(buf[6], buf[7]);
  230.         cellw  = buf[8];
  231.         cellh  = buf[9];
  232.         foreground = buf[10];
  233.         background = buf[11];
  234.  
  235.         while (GetDataBlock(fd, (unsigned char*) buf) != 0) {
  236.             PPM_ASSIGN(xpos, ypos,
  237.                     cmap[CM_RED][v],
  238.                     cmap[CM_GREEN][v],
  239.                     cmap[CM_BLUE][v]);
  240.             ++index;
  241.         }
  242.  
  243.         return FALSE;
  244. #else
  245.         break;
  246. #endif
  247.     case 0xff:        /* Application Extension */
  248.         str = "Application Extension";
  249.         break;
  250.     case 0xfe:        /* Comment Extension */
  251.         str = "Comment Extension";
  252.         while (GetDataBlock(fd, (unsigned char*) buf) != 0) {
  253.             if (showComment)
  254.                 fprintf(stderr, "gif comment: %s\n", buf );
  255.         }
  256.         return FALSE;
  257.     case 0xf9:        /* Graphic Control Extension */
  258.         str = "Graphic Control Extension";
  259.         (void) GetDataBlock(fd, (unsigned char*) buf);
  260.         Gif89.disposal    = (buf[0] >> 2) & 0x7;
  261.         Gif89.inputFlag   = (buf[0] >> 1) & 0x1;
  262.         Gif89.delayTime   = LM_to_uint(buf[1],buf[2]);
  263.         if ((buf[0] & 0x1) != 0)
  264.             Gif89.transparent = buf[3];
  265.  
  266.         while (GetDataBlock(fd, (unsigned char*) buf) != 0)
  267.             ;
  268.         return FALSE;
  269.     default:
  270.         str = buf;
  271.         sprintf(buf, "UNKNOWN (0x%02x)", label);
  272.         break;
  273.     }
  274.  
  275.     fprintf(stderr, "got a '%s' extension - please report this to koblas@mips.com}\n", str );
  276.  
  277.     while (GetDataBlock(fd, (unsigned char*) buf) != 0) ;
  278.  
  279.     return FALSE;
  280. }
  281.  
  282. int    ZeroDataBlock = FALSE;
  283.  
  284. static int GetDataBlock(NXStream *fd, unsigned char * buf)
  285. {
  286.     unsigned char    count;
  287.  
  288.     if (! ReadOK(fd,&count,1)) {
  289.         fprintf(stderr, "error in getting DataBlock size\n" );
  290.         return -1;
  291.     }
  292.  
  293.     ZeroDataBlock = count == 0;
  294.  
  295.     if ((count != 0) && (! ReadOK(fd, buf, count))) {
  296.         fprintf(stderr, "error in reading DataBlock\n" );
  297.         return -1;
  298.     }
  299.  
  300.     return count;
  301. }
  302.  
  303. static int GetCode(NXStream *fd, int code_size, int flag)
  304. {
  305.     static unsigned char    buf[280];
  306.     static int        curbit, lastbit, done, last_byte;
  307.     int            i, j, ret;
  308.     unsigned char        count;
  309.  
  310.     if (flag) {
  311.         curbit = 0;
  312.         lastbit = 0;
  313.         done = FALSE;
  314.         return 0;
  315.     }
  316.  
  317.     if ( (curbit+code_size) >= lastbit) {
  318.         if (done) {
  319.             if (curbit >= lastbit)
  320.                 fprintf(stderr, "ran off the end of my bits\n" );
  321.             return -1;
  322.         }
  323.         buf[0] = buf[last_byte-2];
  324.         buf[1] = buf[last_byte-1];
  325.  
  326.         if ((count = GetDataBlock(fd, &buf[2])) == 0)
  327.             done = TRUE;
  328.  
  329.         last_byte = 2 + count;
  330.         curbit = (curbit - lastbit) + 16;
  331.         lastbit = (2+count)*8 ;
  332.     }
  333.  
  334.     ret = 0;
  335.     for (i = curbit, j = 0; j < code_size; ++i, ++j)
  336.         ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
  337.  
  338.     curbit += code_size;
  339.  
  340.     return ret;
  341. }
  342.  
  343. static int LWZReadByte(NXStream *fd, int flag, int input_code_size)
  344. {
  345.     static int        fresh = FALSE;
  346.     int            code, incode;
  347.     static int        code_size, set_code_size;
  348.     static int        max_code, max_code_size;
  349.     static int        firstcode, oldcode;
  350.     static int        clear_code, end_code;
  351.     static int        table[2][(1<< MAX_LWZ_BITS)];
  352.     static int        stack[(1<<(MAX_LWZ_BITS))*2], *sp;
  353.     register int    i;
  354.  
  355.     if (flag) {
  356.         set_code_size = input_code_size;
  357.         code_size = set_code_size+1;
  358.         clear_code = 1 << set_code_size ;
  359.         end_code = clear_code + 1;
  360.         max_code_size = 2*clear_code;
  361.         max_code = clear_code+2;
  362.  
  363.         GetCode(fd, 0, TRUE);
  364.         
  365.         fresh = TRUE;
  366.  
  367.         for (i = 0; i < clear_code; ++i) {
  368.             table[0][i] = 0;
  369.             table[1][i] = i;
  370.         }
  371.         for (; i < (1<<MAX_LWZ_BITS); ++i)
  372.             table[0][i] = table[1][0] = 0;
  373.  
  374.         sp = stack;
  375.  
  376.         return 0;
  377.     } else if (fresh) {
  378.         fresh = FALSE;
  379.         do {
  380.             firstcode = oldcode =
  381.                 GetCode(fd, code_size, FALSE);
  382.         } while (firstcode == clear_code);
  383.         return firstcode;
  384.     }
  385.  
  386.     if (sp > stack)
  387.         return *--sp;
  388.  
  389.     while ((code = GetCode(fd, code_size, FALSE)) >= 0) {
  390.         if (code == clear_code) {
  391.             for (i = 0; i < clear_code; ++i) {
  392.                 table[0][i] = 0;
  393.                 table[1][i] = i;
  394.             }
  395.             for (; i < (1<<MAX_LWZ_BITS); ++i)
  396.                 table[0][i] = table[1][i] = 0;
  397.             code_size = set_code_size+1;
  398.             max_code_size = 2*clear_code;
  399.             max_code = clear_code+2;
  400.             sp = stack;
  401.             firstcode = oldcode =
  402.                     GetCode(fd, code_size, FALSE);
  403.             return firstcode;
  404.         } else if (code == end_code) {
  405.             int        count;
  406.             unsigned char    buf[260];
  407.  
  408.             if (ZeroDataBlock)
  409.                 return -2;
  410.  
  411.             while ((count = GetDataBlock(fd, buf)) > 0)
  412.                 ;
  413.  
  414.             if (count != 0)
  415.                 fprintf(stderr, "missing EOD in data stream (common occurence)\n");
  416.             return -2;
  417.         }
  418.  
  419.         incode = code;
  420.  
  421.         if (code >= max_code) {
  422.             *sp++ = firstcode;
  423.             code = oldcode;
  424.         }
  425.  
  426.         while (code >= clear_code) {
  427.             *sp++ = table[1][code];
  428.             if (code == table[0][code])
  429.                 fprintf(stderr, "circular table entry BIG ERROR\n");
  430.             code = table[0][code];
  431.         }
  432.  
  433.         *sp++ = firstcode = table[1][code];
  434.  
  435.         if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
  436.             table[0][code] = oldcode;
  437.             table[1][code] = firstcode;
  438.             ++max_code;
  439.             if ((max_code >= max_code_size) &&
  440.                 (max_code_size < (1<<MAX_LWZ_BITS))) {
  441.                 max_code_size *= 2;
  442.                 ++code_size;
  443.             }
  444.         }
  445.  
  446.         oldcode = incode;
  447.  
  448.         if (sp > stack)
  449.             return *--sp;
  450.     }
  451.     return code;
  452. }
  453.  
  454. static void ReadImage(    NXStream             *fd, 
  455.                     int                 len, 
  456.                     int                 height, 
  457.                     unsigned char     cmap[3][MAXCOLORMAPSIZE], 
  458.                     int                 interlace, int ignore)
  459. {
  460.     unsigned char    c;    
  461.     int            v;
  462.     int            xpos = 0, ypos = 0, pass = 0;
  463.     id            image;
  464.  
  465.     /*
  466.     **  Initialize the Compression routines
  467.     */
  468.     if (! ReadOK(fd,&c,1)) {
  469.         error = ERROR_TRUNCATED_FILE;
  470.         fprintf(stderr, "EOF / read error on image data\n" );
  471.         return;
  472.     }
  473.  
  474.     if (LWZReadByte(fd, TRUE, c) < 0)
  475.         fprintf(stderr, "error reading image\n" );
  476.  
  477.     /*
  478.     **  If this is an "uninteresting picture" ignore it.
  479.     */
  480.     if (ignore) {
  481.         if (verbose)
  482.             fprintf(stderr, "skipping image...\n" );
  483.  
  484.         while (LWZReadByte(fd, FALSE, c) >= 0)
  485.             ;
  486.         return;
  487.     }
  488.  
  489.     if ((image = ppm_allocarray(len, height)) == NULL)
  490.         fprintf(stderr, "couldn't alloc space for image\n" );
  491.  
  492.     if (verbose)
  493.         fprintf(stderr, "reading %d by %d%s GIF image\n",
  494.             len, height, interlace ? " interlaced" : "" );
  495.  
  496.     while ((v = LWZReadByte(fd,FALSE,c)) >= 0 ) {
  497.         PPM_ASSIGN(xpos, ypos, cmap[CM_RED][v],
  498.                     cmap[CM_GREEN][v], cmap[CM_BLUE][v]);
  499.  
  500.         ++xpos;
  501.         if (xpos == len) {
  502.             xpos = 0;
  503.             if (interlace) {
  504.                 switch (pass) {
  505.                 case 0:
  506.                 case 1:
  507.                     ypos += 8; break;
  508.                 case 2:
  509.                     ypos += 4; break;
  510.                 case 3:
  511.                     ypos += 2; break;
  512.                 }
  513.  
  514.                 if (ypos >= height) {
  515.                     ++pass;
  516.                     switch (pass) {
  517.                     case 1:
  518.                         ypos = 4; break;
  519.                     case 2:
  520.                         ypos = 2; break;
  521.                     case 3:
  522.                         ypos = 1; break;
  523.                     default:
  524.                         goto fini;
  525.                     }
  526.                 }
  527.             } else {
  528.                 ++ypos;
  529.             }
  530.         }
  531.         if (ypos >= height)
  532.             break;
  533.     }
  534.  
  535. fini:
  536.     if (LWZReadByte(fd,FALSE,c)>=0)
  537.         fprintf(stderr, "too much input data, ignoring extra...\n");
  538.  
  539.     if (verbose)
  540.         fprintf(stderr, "writing output\n");
  541. //    ppm_writeppm(stdout, image, len, height, (pixval) 255, 0 );
  542. }
  543.